/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.archivers.tar;

import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.io.OutputStream;
import static java.lang.String.format;
import static java.util.Locale.UK;

public class BlockWriter
{
	public static final int DefaultRecordsPerBlock = 1;
	private static final byte[] EmptyBlock = createEmptyBlock();
	public static final int BlockSize = 512;
	private static final int NoCurrentBlockNumber = -1;

	private static byte[] createEmptyBlock()
	{
		final byte[] zeroBuffer = new byte[BlockSize];
		for (int i = 0; i < zeroBuffer.length; ++i)
		{
			zeroBuffer[i] = 0;
		}
		return zeroBuffer;
	}

	private final OutputStream outputStream;
	private final int numberOfBlocksPerRecord;
	private int currentBlockNumber;

	public BlockWriter(final @NotNull OutputStream outputStream, final int numberOfBlocksPerRecord)
	{
		this.outputStream = outputStream;
		this.numberOfBlocksPerRecord = numberOfBlocksPerRecord;
		currentBlockNumber = NoCurrentBlockNumber;
	}

	public void writeBlock(final @NotNull byte[] block) throws IOException
	{
		if (block.length != BlockSize)
		{
			throw new IllegalArgumentException(format(UK, "block.length != BlockSize %1$s", BlockSize));
		}
		if (recordAccumulated())
		{
			throw new IllegalStateException("Full!");
		}
		outputStream.write(block);
		outputStream.flush();
		currentBlockNumber++;
		currentBlockNumber = recordAccumulated() ? NoCurrentBlockNumber : currentBlockNumber;
	}

	public void writeEmptyBlocksUntilRecordFull() throws IOException
	{
		while(currentBlockNumber != NoCurrentBlockNumber)
		{
			writeEmptyBlock();
		}
	}

	public void writeEndOfFileRecord() throws IOException
	{
		writeEmptyBlock();
		writeEmptyBlock();
		writeEmptyBlocksUntilRecordFull();
	}

	public void writeIncompleteBlock(final @NotNull byte[] block, final int length) throws IOException
	{
		for (int index = length; index < BlockSize; index++)
		{
			block[index] = 0;
		}
		writeBlock(block);
	}

	private void writeEmptyBlock() throws IOException
	{
		writeBlock(EmptyBlock);
	}

	private boolean recordAccumulated()
	{
		return currentBlockNumber == numberOfBlocksPerRecord;
	}
}
